﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Troschuetz.Random;
using HurSimLib;

namespace WinUI
{
    public partial class formMain : Form, IValidatable
    {
        Simulation simulation;
        MessageService messageService;
        /// <summary>
        /// Service and Waiting Time variables for Analysis
        /// </summary>
        int wday, whour, wmin, wseconds, wmilisecond, sday, shour, smin, sseconds, smilisecond;
        public formMain()
        {
            InitializeComponent();
        }

        private void dtpEndTime_ValueChanged(object sender, EventArgs e)
        {
            //simulation.EndDate = dtpEndTime.Value;
            simulation.EndDate = simulation.StartDate.AddMinutes(10);
        }

        private void dtpStartTime_ValueChanged(object sender, EventArgs e)
        {
            simulation.StartDate = dtpStartTime.Value;
        }

        private void cmbDistribution_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (DoSkip != true)
            {
                Enums.Distibution distribution = cmbDistribution.SelectedItem.ToString().GetEnumFromString<Enums.Distibution>();
                if (simulation.Generator != null)
                {
                    switch (distribution)
                    {
                        case Enums.Distibution.ExponentialDistribution:
                            simulation.Distribution = new ExponentialDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.NormalDistribution:
                            simulation.Distribution = new NormalDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.PowerDistribution:
                            simulation.Distribution = new PowerDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.TriangularDistribution:
                            simulation.Distribution = new TriangularDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.WeibullDistribution:
                            simulation.Distribution = new WeibullDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.RayleighDistribution:
                            simulation.Distribution = new RayleighDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.BernoulliDistribution:
                            simulation.Distribution = new BernoulliDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.BinomialDistribution:
                            simulation.Distribution = new BinomialDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.DiscreteUniformDistribution:
                            simulation.Distribution = new DiscreteUniformDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.GeometricDistribution:
                            simulation.Distribution = new GeometricDistribution(simulation.Generator);
                            break;
                        case Enums.Distibution.PoissonDistribution:
                            simulation.Distribution = new PoissonDistribution(simulation.Generator);
                            break;
                        default:
                            simulation.Distribution = new NormalDistribution(simulation.Generator);
                            break;
                    }
                }
                else
                {
                    messageService.ShowErrorMessage("Lüften Generator Seçiniz");
                }
            }
        }

        private void cmbProcessType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (DoSkip != true)
            {
                Enums.ProcessType processType = cmbProcessType.SelectedItem.ToString().GetEnumFromString<Enums.ProcessType>();
                switch (processType)
                {
                    case Enums.ProcessType.Normal:
                        simulation.Process = new HurProcess();
                        break;
                    case Enums.ProcessType.Delay:
                        break;
                    case Enums.ProcessType.Service:
                        simulation.Process = new HurServiceProcess();
                        break;
                    default:
                        break;
                }
            }
        }

        private void cmbRandomGeneratorType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (DoSkip != true)
            {
                Enums.RandomGenerator randomGenerator = cmbRandomGeneratorType.SelectedItem.ToString().GetEnumFromString<Enums.RandomGenerator>();
                switch (randomGenerator)
                {
                    case Enums.RandomGenerator.ALFGenerator:
                        simulation.Generator = new ALFGenerator();
                        break;
                    case Enums.RandomGenerator.MT19937Generator:
                        simulation.Generator = new MT19937Generator();
                        break;
                    case Enums.RandomGenerator.StandardGenerator:
                        simulation.Generator = new StandardGenerator();
                        break;
                    case Enums.RandomGenerator.XorShift128Generator:
                        simulation.Generator = new XorShift128Generator();
                        break;
                    default:
                        simulation.Generator = new StandardGenerator();
                        break;
                }
            }
        }

        private void cmbTimeUnit_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (DoSkip != true)
            {
                Enums.TimeUnit timeUnit = cmbTimeUnit.SelectedItem.ToString().GetEnumFromString<Enums.TimeUnit>();
                switch (timeUnit)
                {
                    case Enums.TimeUnit.Day:
                        break;
                    case Enums.TimeUnit.Hour:
                        {
                            groupBoxShiftConfig.Enabled = true;
                            break;
                        }
                    case Enums.TimeUnit.Minute:
                        break;
                    case Enums.TimeUnit.Second:
                        break;
                    case Enums.TimeUnit.MilliSecond:
                        break;
                    default:
                        break;
                }
            }
        }

        private void btnExecute_Click(object sender, EventArgs e)
        {
            ValidateResult result = ValidateUI();
            if (result.IsValid == false)
            {
                MessageBox.Show(result.Message);
            }
            else
            {
                ExecSimulation();
                ExecSimulation();
                Analsysis();
                ClearUI();
            }
        }

        private void Analsysis()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(string.Format("Toplam Giren Nesne : {0}\n", simulation.HurObjectGenerator.NextProcess.Entryqueue.Count));

            foreach (var item in simulation.HurObjectGenerator.NextProcess.Entryqueue)
            {
                whour += item.TotalWaitingTime.Hour;
                wmin += item.TotalWaitingTime.Minute;
                wseconds += item.TotalWaitingTime.Second;
                wmilisecond += item.TotalWaitingTime.Millisecond;

                shour += item.TotalServiceTime.Hour;
                smin += item.TotalServiceTime.Minute;
                sseconds += item.TotalServiceTime.Second;
                smilisecond += item.TotalServiceTime.Millisecond;
            }
            sb.Append("--- BEKLEME ANALIZI --\n");
            sb.Append(string.Format("Toplam Bekleme Zamanı Saat: {0}\n", whour));
            sb.Append(string.Format("Toplam Bekleme Zamanı Dakika: {0}\n", wmin));
            sb.Append(string.Format("Toplam Bekleme Zamanı Saniye: {0}\n", wseconds));
            sb.Append(string.Format("Toplam Bekleme Zamanı Milisaniye: {0}\n", wmilisecond));
            sb.Append("--- SERVİS ANALIZI --\n");
            sb.Append(string.Format("Toplam Servis Zamanı Saat: {0}\n", shour));
            sb.Append(string.Format("Toplam Servis Zamanı Dakika: {0}\n", smin));
            sb.Append(string.Format("Toplam Servis Zamanı Saniye: {0}\n", sseconds));
            sb.Append(string.Format("Toplam Servis Zamanı Milisaniye: {0}\n", smilisecond));
            sb.AppendLine();

            //TimeSpan ts = simulation.EndDate - simulation.StartDate;
            //sb.AppendLine(string.Format("Toplam Boş Zaman :{0}", ts));

            logAnalysis.Text = sb.ToString();
        }

        private void ExecSimulation()
        {
            simulation.StartDate = dtpStartTime.Value;
            simulation.EndDate = simulation.StartDate.AddMinutes(10);
            _GenerateSimulationObjects((int)nudObjectCount.Value);
            logTextArea.Text = simulation.Exec();
        }

        #region Private Functions
        /// <summary>
        /// Simulasyon için hazırlanan gerekli konfigurasyonlara göre nesnelerin yaratılması işlemnin yapar
        /// </summary>
        /// <param name="objCount"></param>
        private void _GenerateSimulationObjects(int objCount)
        {
            for (int i = 0; i < objCount; i++)
            {
                simulation.HurObjectGenerator.Generate();
            }
        }
        void ClearUI()
        {
            DoSkip = true;
            cmbDistribution.SelectedIndex = -1;
            cmbProcessType.SelectedIndex = -1;
            cmbRandomGeneratorType.SelectedIndex = -1;
            cmbTimeUnit.SelectedIndex = -1;
            dtpStartTime.Value = DateTime.Now;
            dtpEndTime.Value = DateTime.Now;
            nudObjectCount.Value = 0;
            nudShift.Value = 0;
            simulation.Distribution = null;
            simulation.EndDate = default(DateTime);
            simulation.StartDate = default(DateTime);
            simulation.Process = null;
            DoSkip = false;
        }
        #endregion
        #region IValidatable Interface Members
        /// <summary>
        /// Formun simulasyuon için hazır olup olmadığının kontrolunu yapar.
        /// </summary>
        /// <returns></returns>
        public ValidateResult ValidateUI()
        {
            ValidateResult result = new ValidateResult();
            if (cmbDistribution.SelectedItem == null)
            {
                result.IsValid = false;
                result.Message = "Lütfen Dağılım Bilgisi Girin";
                return result;
            }
            if (dtpEndTime.Value == dtpStartTime.Value)
            {
                result.IsValid = false;
                result.Message = "Lütfen Bitiş Tarihi Bilgisi Girin";
                return result;
            }
            if (cmbProcessType.SelectedItem == null)
            {
                result.IsValid = false;
                result.Message = "Lütfen İşlem Tip Bilgisi Girin";
                return result;
            }
            if (cmbRandomGeneratorType.SelectedItem == null)
            {
                result.IsValid = false;
                result.Message = "Lütfen Rastgele Üretici Bilgisi Girin";
                return result;
            }
            if (cmbTimeUnit.SelectedItem == null)
            {
                result.IsValid = false;
                result.Message = "Lütfen Zaman Birimi Bilgisi Girin";
                return result;
            }
            if (nudObjectCount.Value == 0)
            {
                result.IsValid = false;
                result.Message = "Lütfen Nesne Sayısı Bilgisi Girin";
                return result;
            }
            return result;
        }
        #endregion

        private void formMain_Load(object sender, EventArgs e)
        {
            simulation = new Simulation();
            messageService = new MessageService();
            DoSkip = false;
        }

        public bool DoSkip { get; set; }
    }
}
